package com.triones.api.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.annotation.Translation;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.php.BankCardApplyStatus;
import com.ruoyi.common.enums.php.OpenCardStatus;
import com.ruoyi.common.enums.php.OpenCardTransactionType;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.helper.LoginHelper;
import com.ruoyi.common.utils.DateUtil;
import com.ruoyi.common.utils.SnowflakeIdWorker;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.email.EmailValidationUtils;
import com.ruoyi.system.domain.SysConfig;
import com.triones.api.entity.*;
import com.triones.api.entity.bo.*;
import com.triones.api.entity.param.*;
import com.triones.api.entity.vo.*;
import com.triones.api.mapper.*;
import com.triones.api.service.BankCardService;
import com.triones.api.service.FaitWalletService;
import com.triones.api.service.third.LeptageService;
import com.triones.api.service.third.PhotonPayService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 银行卡 -业务实现
 */
@Service
@RequiredArgsConstructor
public class BankCardServiceImpl implements BankCardService {

    private final BankCardMapper bankCardMapper;

    private final CardBinMapper cardBinMapper;

    private final PhotonPayService photonPayService;

    private final BankCardFreezeRecordMapper bankCardFreezeRecordMapper;

    private final BankCardTxnMapper bankCardTxnMapper;

    private final KycVerifyMapper kycVerifyMapper;

    private final RecipientMapper recipientMapper;

    private final LeptageService leptageService;

    private final CardholderMapper cardholderMapper;

    private final FaitWalletMapper faitWalletMapper;

    private final FeeThaliMapper feeThaliMapper;

    private final EcWalletBillMapper ecWalletBillMapper;

    private final BankCardUpdateRecordMapper bankCardUpdateRecordMapper;

    private final CardMgrFeeMapper cardMgrFeeMapper;

    private final FaitWalletService faitWalletService;

    private final BankCardTypeMapper bankCardTypeMapper;

    @Override
    public TableDataInfo<CustomMemberBankCardVO> pageList(BankCardParams bankCardParams, PageQuery pageQuery) {
        QueryWrapper<Object> wrapper = Wrappers.query();
        wrapper.orderByDesc("tm.create_time");
        Page<CustomMemberBankCardVO> result = bankCardMapper.selectPageList(pageQuery.build(), wrapper);
        return TableDataInfo.build(result);
    }

    @Override
    public List<BankCardVO> list(Long uid,String type, String cardStatus) {
        LambdaQueryWrapper<BankCardDO> lqw = Wrappers.lambdaQuery();
        lqw.eq(BankCardDO::getUid, uid)
        .eq(BankCardDO::getStatus, BankCardApplyStatus.SUCCEED.getCode())
        .eq(StringUtils.isNotBlank(type),BankCardDO::getCardFormFactor, type)
        .eq(StringUtils.isNotBlank(cardStatus),BankCardDO::getCardStatus, cardStatus)
        .orderByDesc(BankCardDO::getCreateTime);
        return bankCardMapper.selectVoList(lqw);
    }

    @Override
    public TableDataInfo<BankCardVO> applyPageList(ApplyBankCardParams applyBankCardParams, PageQuery pageQuery) {
        Map<String, Object> params = applyBankCardParams.getParams();
        LambdaQueryWrapper<BankCardDO> lqw = new LambdaQueryWrapper<BankCardDO>();
        Page<BankCardVO> result = bankCardMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    @Override
    public CardBinVO cardBinDetail(String cardBin) {
        return cardBinMapper.selectVoOne(new LambdaQueryWrapper<CardBinDO>().eq(CardBinDO::getCardBin, cardBin).last("limit 1"));
    }

    @Override
    public CustomBankCardVO applyDetail(Long id) {
        return bankCardMapper.applyDetail(id);
    }

    @Override
    public TableDataInfo<BankCardVO> apiPageList(PageQuery pageQuery) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser == null) {
            throw new ServiceException("当前用户退出登录!");
        }
        LambdaQueryWrapper<BankCardDO> lqw = new LambdaQueryWrapper<BankCardDO>();
        lqw.eq(BankCardDO::getUid, loginUser.getUserId());
        lqw.eq(BankCardDO::getStatus, BankCardApplyStatus.SUCCEED.getCode());
        lqw.orderByDesc(BankCardDO::getCreateTime);
        Page<BankCardVO> result = bankCardMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    @Override
    public TableDataInfo<BankCardVO> apiApplyPageList(PageQuery pageQuery) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser == null) {
            throw new ServiceException("当前用户退出登录!");
        }
        LambdaQueryWrapper<BankCardDO> lqw = new LambdaQueryWrapper<BankCardDO>();
        lqw.eq(BankCardDO::getUid, loginUser.getUserId());
        lqw.orderByDesc(BankCardDO::getCreateTime);
        Page<BankCardVO> result = bankCardMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    @Override
    public CustomBankCardVO apiDetail(Long id) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser == null) {
            throw new ServiceException("当前用户退出登录!");
        }
        CustomBankCardVO customBankCardVO = bankCardMapper.bankCardDetail(id, loginUser.getUserId());
        if (customBankCardVO == null) {
            throw new ServiceException("银行卡不存在!");
        }

        /**
         * 统计日交易剩余额度
         */
        BigDecimal surplusMaxOnDaily = bankCardMapper.statSurplusMaxOnDaily(customBankCardVO.getCardId());
        customBankCardVO.setSurplusMaxOnDaily(Convert.toStr(Convert.toBigDecimal(customBankCardVO.getMaxOnDaily()).add(Convert.toBigDecimal(surplusMaxOnDaily, BigDecimal.ZERO)).setScale(2, RoundingMode.HALF_UP)));

        /**
         * 查询月交易剩余额度
         */
        BigDecimal surplusMaxOnMonthly = bankCardMapper.statSurplusMaxOnMonthly(customBankCardVO.getCardId());
        customBankCardVO.setSurplusMaxOnMonthly(Convert.toStr(Convert.toBigDecimal(customBankCardVO.getMaxOnMonthly()).add(Convert.toBigDecimal(surplusMaxOnMonthly, BigDecimal.ZERO)).setScale(2, RoundingMode.HALF_UP)));
        return customBankCardVO;
    }

    @Override
    public boolean checkCardBin(CardBinParams params) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser == null) {
            throw new ServiceException("当前用户退出登录!");
        }
        List<Map> cardBin = photonPayService.getCardBin(params);
        if (cardBin.size() == 0) {
            throw new ServiceException("没有可以申请的卡信息");
        }
        for (Map map : cardBin) {
            if ("Unlimited".equals(map.get("remainingAvailableCard")) || !"0".equals(map.get("remainingAvailableCard"))) {
                return true;
            }
        }
        throw new ServiceException("没有可以申请的卡信息");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean cardApply(BankCardBO bo) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser == null) {
            throw new ServiceException("当前用户退出登录!");
        }

        /**
         * 实体卡信息校验
         */
        if (!"virtual_card".equals(bo.getCardFormFactor())) {
            /**
             * 发送新增收件人请求
             */
            if (bo.getRecipientFirstName() == null) {
                throw new ServiceException("请输入收件人名字");
            }
            if (bo.getRecipientLastName() == null) {
                throw new ServiceException("请输入收件人姓氏");
            }
            if (bo.getMobilePrefix() == null) {
                throw new ServiceException("请输入手机号前缀（包括区号）");
            }
            if (bo.getMobile() == null) {
                throw new ServiceException("请输入手机号");
            }
            if (bo.getCountry() == null) {
                throw new ServiceException("请输入国籍国家");
            }
            if (bo.getState() == null) {
                throw new ServiceException("请输入省份/州");
            }
            if (bo.getCity() == null) {
                throw new ServiceException("请输入城市");
            }
            if (bo.getAddressLine1() == null) {
                throw new ServiceException("请输入详细地址第一行地址");
            }
            if (bo.getPostalCode() == null) {
                throw new ServiceException("请输入邮政编码");
            }
        }

        /**
         * kyc信息
         */
        KycVerifyDO kycVerifyDO = kycVerifyMapper.selectOne(new LambdaQueryWrapper<KycVerifyDO>()
            .eq(KycVerifyDO::getUid, loginUser.getUserId()).eq(KycVerifyDO::getAuditStatus,"1")
            .orderByDesc(KycVerifyDO::getCreateTime).last("limit 1"));
        if (kycVerifyDO == null) {
            throw new ServiceException("kyc审核申请未通过，暂无开卡资格");
        }

        /**
         * 查询卡对应的钱包
         */
        FaitWalletDO wallet = faitWalletMapper.selectOne(new LambdaQueryWrapper<FaitWalletDO>().eq(FaitWalletDO::getUid, loginUser.getUserId()).eq(FaitWalletDO::getCurrency, "USD"));
        if (wallet == null) {
            throw new ServiceException("钱包信息不存在");
        }

        /**
         * 查询开卡费用
         */
        BigDecimal balance = Convert.toBigDecimal(wallet.getAmount());
        BigDecimal openCardFee = BigDecimal.ZERO;
        if ("virtual_card".equals(bo.getCardFormFactor())) {
            FeeThaliVO feeThaliVO = feeThaliMapper.selectVoOne(new LambdaQueryWrapper<FeeThaliDO>()
                .eq(FeeThaliDO::getType, "open_card")
                .eq(FeeThaliDO::getStatus, "0")
                .last("limit 1"));
            if (feeThaliVO != null) {
                openCardFee = Convert.toBigDecimal(feeThaliVO.getFeeConfig()).setScale(2, RoundingMode.HALF_UP);
                if (balance.compareTo(openCardFee) == -1) {
                    throw new ServiceException("钱包余额不足");
                }
            }
        } else {
            throw new ServiceException("很抱歉，实体卡暂不支持请您谅解！");
        }

        String requestId = Convert.toStr(SnowflakeIdWorker.generateUniqueId());
        BankCardDO bankCardDO = new BankCardDO();
        BankCardBodyBO cardBodyBO = new BankCardBodyBO();
        cardBodyBO.setCardCurrency("USD");
        cardBodyBO.setRequestId(requestId);
        cardBodyBO.setCardScheme(bo.getCardScheme());
        cardBodyBO.setCardType("share");
        cardBodyBO.setCardFormFactor(bo.getCardFormFactor());
        cardBodyBO.setMaxOnDaily("20000.00");
        cardBodyBO.setMaxOnMonthly("20000.00");
        cardBodyBO.setMaxOnPercent("20000.00");

        /**
         * 检查卡bin信息
         */
        CardBinParams params = new CardBinParams();
        params.setCardCurrency("USD");
        params.setCardFormFactor(bo.getCardFormFactor());
        params.setCardScheme(bo.getCardScheme());
        params.setCardType("share");
        List<Map> cardBin = photonPayService.getCardBin(params);
        String cardBinId = "";
        if (cardBin.size() == 0) {
            throw new ServiceException("没有可以申请的卡信息");
        }
        for (Map map : cardBin) {
            if ("Unlimited".equals(map.get("remainingAvailableCard")) || !"0".equals(map.get("remainingAvailableCard"))) {
                cardBinId = Convert.toStr(map.get("cardBin"));
                break;
            }
        }

//        /**
//         * 测试环境使用
//         */
//        cardBinId = "553437";

        cardBodyBO.setCardBin(cardBinId);
        bankCardDO.setCardBin(cardBinId);
        CardholderVO cardholderVO = cardholderMapper.selectVoOne(new LambdaQueryWrapper<CardholderDO>()
            .eq(CardholderDO::getUid, loginUser.getUserId())
            .eq(CardholderDO::getStatus, "normal")
            .orderByDesc(CardholderDO::getCreateTime)
            .last("limit 1"));
        if (cardholderVO == null) {
            /**
             * 发送新增用卡人请求
             */
            CardholderBodyBO cardholderBodyBO = new CardholderBodyBO();
            BeanUtil.copyProperties(kycVerifyDO,cardholderBodyBO);
            cardholderBodyBO.setMobile(kycVerifyDO.getPhone());
            cardholderBodyBO.setMobilePrefix(kycVerifyDO.getPhoneAreaCode());
            Map addCardholderResponseMap = photonPayService.addCardholder(cardholderBodyBO);
            if (addCardholderResponseMap == null) {
                throw new ServiceException("新增用卡人失败！");
            }
            String cardholderStatus = Convert.toStr(addCardholderResponseMap.get("status"));
            if (!"normal".equals(cardholderStatus)) {
                throw new ServiceException("用卡人信息暂不可用！");
            }
            String cardholderId = Convert.toStr(addCardholderResponseMap.get("cardholderId"));
            CardholderDO cardholderDO = new CardholderDO();
            BeanUtil.copyProperties(cardholderBodyBO,cardholderDO);
            cardholderDO.setUid(loginUser.getUserId());
            cardholderDO.setCreateTime(System.currentTimeMillis());
            cardholderDO.setCardholderId(cardholderId);
            cardholderDO.setStatus(cardholderStatus);
            cardholderDO.setCardholderReviewStatus(Convert.toStr(addCardholderResponseMap.get("cardholderReviewStatus")));
            cardholderDO.setIdInfoRequirement(Convert.toStr(addCardholderResponseMap.get("idInfoRequirement")));
            cardholderDO.setReason(Convert.toStr(addCardholderResponseMap.get("reason")));
            cardholderMapper.insert(cardholderDO);
            cardBodyBO.setCardholderId(cardholderId);
            bankCardDO.setCardholderId(cardholderId);
        } else {
            cardBodyBO.setCardholderId(cardholderVO.getCardholderId());
            bankCardDO.setCardholderId(cardholderVO.getCardholderId());
        }

        /**
         * 处理是否是实体卡
         */
        if (!"virtual_card".equals(bo.getCardFormFactor())) {
            /**
             * 发送新增收件人请求
             */
            RecipientBodyBO recipientBodyBO = new RecipientBodyBO();
            BeanUtil.copyProperties(bo,recipientBodyBO);
            Map addRecipientResponseMap = photonPayService.addRecipient(recipientBodyBO);
            String recipientId = Convert.toStr(addRecipientResponseMap.get("recipientId"));
            RecipientDO recipientDO = new RecipientDO();
            BeanUtil.copyProperties(bo,recipientDO);
            recipientDO.setCreateTime(System.currentTimeMillis());
            recipientDO.setUid(loginUser.getUserId());
            recipientDO.setRecipientStatus(Convert.toStr(addRecipientResponseMap.get("recipientStatus")));
            recipientDO.setRecipientId(recipientId);
            recipientMapper.insert(recipientDO);
            cardBodyBO.setRecipientId(recipientId);
            bankCardDO.setRecipientId(recipientId);
        }
        cardBodyBO.setTransactionLimitType("limited");
        cardBodyBO.setTransactionLimit(wallet.getAmount());
        bankCardDO.setUid(loginUser.getUserId());
        bankCardDO.setCreateTime(System.currentTimeMillis());
        BeanUtil.copyProperties(cardBodyBO,bankCardDO);
        /**
         * 发送请求
         */
        Map openCardResponseMap = photonPayService.openCard(cardBodyBO);
        if (openCardResponseMap == null) {
            throw new ServiceException("卡片申请失败");
        }
        Map cardDetail = (Map) openCardResponseMap.get("cardDetail");
        if (cardDetail != null) {
            bankCardDO.setCardId(Convert.toStr(cardDetail.get("cardId")));
            bankCardDO.setCardNo(Convert.toStr(cardDetail.get("cardNo")));
            bankCardDO.setCardStatus(Convert.toStr(cardDetail.get("cardStatus")));
            bankCardDO.setCvv(Convert.toStr(cardDetail.get("cvv")));
            bankCardDO.setExpirationDate(Convert.toStr(cardDetail.get("expirationDate")));
        }
        bankCardDO.setStatus(Convert.toStr(openCardResponseMap.get("status")));

        bankCardMapper.insert(bankCardDO);

        /**
         * 扣除开卡费
         */
        BigDecimal balanceFund = balance.subtract(openCardFee);
        EcWalletBillDO ecWalletBillDO = new EcWalletBillDO();
        ecWalletBillDO.setUid(loginUser.getUserId());
        ecWalletBillDO.setEcId(wallet.getId());
        ecWalletBillDO.setAccountHistoryNo(bankCardDO.getCardNo());
        ecWalletBillDO.setAccountNo(Convert.toStr(wallet.getId()));
        ecWalletBillDO.setAmount(openCardFee);
        ecWalletBillDO.setBalanceFund(balanceFund);
        ecWalletBillDO.setCurrency("USD");
        ecWalletBillDO.setTransactedAt(Convert.toStr(System.currentTimeMillis()));
        ecWalletBillDO.setTxnType(OpenCardTransactionType.OPEN_CARD_FEE.getCode());
        ecWalletBillDO.setTransactionNotes(OpenCardTransactionType.OPEN_CARD_FEE.getInfo());
        ecWalletBillDO.setStatus("success");
        ecWalletBillDO.setTransactionType("decrease");
        ecWalletBillMapper.insert(ecWalletBillDO);

        /**
         * 更新钱包
         */
        faitWalletService.fiatWalletCardUpdate(wallet.getUid(),"USD",openCardFee,"decrease",null);

        /**
         * 增加当月卡片管理费（待收）
         */
        FeeThaliVO feeThaliVO = feeThaliMapper.selectVoOne(new LambdaQueryWrapper<FeeThaliDO>()
            .eq(FeeThaliDO::getType, "card_mgt")
            .eq(FeeThaliDO::getStatus, "0")
            .last("limit 1"));
        if (feeThaliVO != null) {
            BigDecimal cardMgt = Convert.toBigDecimal(feeThaliVO.getFeeConfig()).setScale(2, RoundingMode.HALF_UP);
            CardMgrFeeDO cardMgrFeeDO = new CardMgrFeeDO();
            cardMgrFeeDO.setCardId(bankCardDO.getCardId());
            cardMgrFeeDO.setCardNo(bankCardDO.getCardNo());
            cardMgrFeeDO.setUid(bankCardDO.getUid());
            cardMgrFeeDO.setCollectMonth(DateUtil.timestampToDateStr());
            cardMgrFeeDO.setCreateAt(System.currentTimeMillis());
            cardMgrFeeDO.setCollectAmount(cardMgt);
            if (DateUtil.timestampToDay() > 16) {
                cardMgrFeeDO.setCollectAmount(cardMgt.divide(Convert.toBigDecimal(2),2,BigDecimal.ROUND_HALF_UP));
            }
            cardMgrFeeDO.setStatus("0");
            cardMgrFeeMapper.insert(cardMgrFeeDO);
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean cardActivate(CardActivateBO bo) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser == null) {
            throw new ServiceException("当前用户退出登录!");
        }
        BankCardDO bankCardDO = bankCardMapper.selectOne(new LambdaQueryWrapper<BankCardDO>().eq(BankCardDO::getCardId, bo.getCardId()).eq(BankCardDO::getUid, loginUser.getUserId()).last("limit 1"));
        if (bankCardDO == null) {
            throw new ServiceException("卡片信息不存在");
        }
        if (!OpenCardStatus.UNACTIVATED.getCode().equals(bankCardDO.getCardStatus())) {
            throw new ServiceException("卡片已激活，无需在激活");
        }
        Map responseMap = photonPayService.cardActivate(bo);
        bankCardDO.setCardStatus(Convert.toStr(responseMap.get("cardStatus")));
        bankCardDO.setActivationTime(Convert.toStr(responseMap.get("activationTime")));
        return bankCardMapper.updateById(bankCardDO) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean freezeCard(BankCardFreezeRecordBO bo) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser == null) {
            throw new ServiceException("当前用户退出登录!");
        }
        BankCardDO bankCardDO = bankCardMapper.selectOne(new LambdaQueryWrapper<BankCardDO>()
            .eq(BankCardDO::getCardId, bo.getCardId())
            .eq(BankCardDO::getUid, loginUser.getUserId())
            .last("limit 1"));
        if (bankCardDO == null) {
            throw new ServiceException("卡片信息不存在");
        }

        /**
         * 发送申请
         */
        String requestId = Convert.toStr(SnowflakeIdWorker.generateUniqueId());
        BankCardFreezeRecordDO bankCardFreezeRecordDO = new BankCardFreezeRecordDO();
        bankCardFreezeRecordDO.setCardId(bo.getCardId());
        bankCardFreezeRecordDO.setStatus(bo.getStatus());
        bankCardFreezeRecordDO.setRequestId(requestId);
        photonPayService.freezeCard(bankCardFreezeRecordDO);
        bankCardFreezeRecordDO.setCreateTime(System.currentTimeMillis());
        bankCardFreezeRecordDO.setUid(loginUser.getUserId());
        bankCardFreezeRecordDO.setCardId(bo.getCardId());
        bankCardFreezeRecordDO.setRequestId(requestId);
        bankCardFreezeRecordDO.setStatus(bo.getStatus());
        return bankCardFreezeRecordMapper.insert(bankCardFreezeRecordDO) > 0;
    }

    @Override
    public TableDataInfo<BankCardTxnVO> cardTnx(BankCardTxnParams params, PageQuery pageQuery) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser == null) {
            throw new ServiceException("当前用户退出登录!");
        }
        LambdaQueryWrapper<BankCardTxnDO> lqw = Wrappers.lambdaQuery();
        lqw.eq(BankCardTxnDO::getUid, loginUser.getUserId());
        lqw.eq(StringUtils.isNotEmpty(params.getCardId()),BankCardTxnDO::getCardId, params.getCardId());
        if ("withdrawals".equals(params.getTransactionType())) {
            lqw.in(BankCardTxnDO::getTransactionType, OpenCardTransactionType.ATM_WITHDRAWALS.getCode());
        }
        if ("auth".equals(params.getTransactionType())) {
            lqw.in(BankCardTxnDO::getTransactionType, OpenCardTransactionType.AUTH.getCode(), OpenCardTransactionType.SERVICE_FEE.getCode());
        }
        if (params.getDateYearMonth() != null) {
            lqw.apply("DATE_FORMAT(DATE_FORMAT(STR_TO_DATE(create_at, '%Y-%m-%dT%H:%i:%s'), '%Y-%m-%d %H:%i:%s'), '%Y-%m') = {0}", params.getDateYearMonth());
        }
        Page<BankCardTxnVO> result = bankCardTxnMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    @Override
    public BankCardTxnVO cardTnxDetail(Long id) {
        return bankCardTxnMapper.selectVoById(id);
    }

    @Override
    public CustomBankCardDetailVO bankCardDetail(Long id) {
        return bankCardMapper.sysBankCardDetail(id);
    }

    @Override
    public TableDataInfo<CustomBankCardStatVO> statList(BankCardStatParams params, PageQuery pageQuery) {
        QueryWrapper<Object> wrapper = Wrappers.query();
        Page<CustomBankCardStatVO> result = bankCardMapper.statList(pageQuery.build(), wrapper);
        return TableDataInfo.build(result);
    }

    @Override
    public TableDataInfo<CustomBankCardTxnVO> bankCardTxPageList(CustomBankCardTxnParams params, PageQuery pageQuery) {
        QueryWrapper<Object> wrapper = Wrappers.query();
        wrapper.like(StringUtils.isNotEmpty(params.getCardNo()),"tbc.card_no",params.getCardNo())
            .and(StringUtils.isNotEmpty(params.getCardholder()),
                w -> w.like("tc.first_name",params.getCardholder()).or()
                    .like("tc.last_name",params.getCardholder()));
        Page<CustomBankCardTxnVO> result = bankCardMapper.bankCardTxPageList(pageQuery.build(), wrapper);
        return TableDataInfo.build(result);
    }

    @Override
    public Map textTxn(SandBoxTransactionRequestBodyBO bo) {
        return photonPayService.textTxn(bo);
    }

    @Override
    public List<BankCardVO> listAll() {
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser == null) {
            throw new ServiceException("当前用户退出登录!");
        }
        LambdaQueryWrapper<BankCardDO> lqw = Wrappers.lambdaQuery();
        lqw.eq(BankCardDO::getUid, loginUser.getUserId())
            .eq(BankCardDO::getStatus, BankCardApplyStatus.SUCCEED.getCode())
            .orderByDesc(BankCardDO::getCreateTime);
        return bankCardMapper.selectVoList(lqw);
    }

    @Override
    public Map getBankCardDetail(String cardId) {
        CardDetailParams cardDetailParams = new CardDetailParams();
        cardDetailParams.setCardId(cardId);
        return photonPayService.getCardDetail(cardDetailParams);
    }

    @Override
    public Map mockCardUpdate(UpdateCardBO bo) {
        /**
         * 卡更新（三方）
         */
        String requestId = Convert.toStr(SnowflakeIdWorker.generateUniqueId());
        UpdateCardRequestBodyBO updateCardRequestBodyBO = new UpdateCardRequestBodyBO();
        updateCardRequestBodyBO.setCardId(bo.getCardId());
        updateCardRequestBodyBO.setCardFormFactor(bo.getCardFormFactor());
        updateCardRequestBodyBO.setRequestId(requestId);
        updateCardRequestBodyBO.setMaxOnDaily(bo.getMaxOnDaily());
        updateCardRequestBodyBO.setMaxOnMonthly(bo.getMaxOnMonthly());
        updateCardRequestBodyBO.setMaxOnPercent(bo.getMaxOnPercent());
        updateCardRequestBodyBO.setNickname(bo.getNickname());
        updateCardRequestBodyBO.setTransactionLimit(bo.getTransactionLimit());
        updateCardRequestBodyBO.setTransactionLimitType(bo.getTransactionLimitType());
        updateCardRequestBodyBO.setTransactionLimitChangeType(bo.getTransactionLimitChangeType());
        Map map = photonPayService.updateCard(updateCardRequestBodyBO);
        return map;
    }

    @Override
    public TableDataInfo<BankCardTypeVO> typePageList(BankCardTypeDO dto, PageQuery pageQuery) {
        LambdaQueryWrapper<BankCardTypeDO> lqw = new LambdaQueryWrapper<BankCardTypeDO>();
        lqw.like(ObjectUtil.isNotEmpty(dto.getCardScheme()),  BankCardTypeDO::getCardScheme, dto.getCardScheme());
        lqw.eq(ObjectUtil.isNotEmpty(dto.getCardFormFactor()),  BankCardTypeDO::getCardFormFactor, dto.getCardFormFactor());
        lqw.eq(BankCardTypeDO::getDel, "0");
        Page<BankCardTypeVO> result = bankCardTypeMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    @Override
    public boolean checkCardSchemeAndCardFormFactor(BankCardTypeDO dto) {
        boolean exist = bankCardTypeMapper.exists(new LambdaQueryWrapper<BankCardTypeDO>()
            .eq(BankCardTypeDO::getCardScheme, dto.getCardScheme())
            .eq(BankCardTypeDO::getCardFormFactor, dto.getCardFormFactor())
            .ne(ObjectUtil.isNotNull(dto.getId()), BankCardTypeDO::getId, dto.getId()));
        return !exist;
    }

    @Override
    public void addBankcardType(BankCardTypeDO dto) {
        dto.setCreateAt(System.currentTimeMillis());
        dto.setUpdateAt(System.currentTimeMillis());
        bankCardTypeMapper.insert(dto);
    }

    @Override
    public void editBankcardType(BankCardTypeDO dto) {
        dto.setUpdateAt(System.currentTimeMillis());
        bankCardTypeMapper.updateById(dto);
    }

    @Override
    public BankCardTypeVO getInfo(Long id) {
        return bankCardTypeMapper.selectVoById(id);
    }

    @Override
    public boolean updateShowStatus(BankCardTypeDO dto) {
        BankCardTypeDO bankCardTypeDO = bankCardTypeMapper.selectById(dto.getId());
        if (bankCardTypeDO == null) {
            throw new ServiceException("未找到该记录");
        }
        bankCardTypeDO.setShowStatus(dto.getShowStatus());
        return bankCardTypeMapper.updateById(bankCardTypeDO) > 0;
    }

    @Override
    public void removeBankcardType(Long id) {
        BankCardTypeDO bankCardTypeDO = bankCardTypeMapper.selectById(id);
        if (bankCardTypeDO == null) {
            throw new ServiceException("数据不存在");
        }
        bankCardTypeDO.setDel("1");
        bankCardTypeMapper.updateById(bankCardTypeDO);
    }

    @Override
    public List<BankCardTypeVO> cardTypeList() {
        return bankCardTypeMapper.selectVoList(new LambdaQueryWrapper<BankCardTypeDO>()
            .eq(BankCardTypeDO::getDel, "0")
            .eq(BankCardTypeDO::getShowStatus, "0"));
    }

    /**
     * 定时收取卡片管理费用（每个小时执行一次）
     */
//    @Scheduled(cron = "0 0 * * * ?")
    public void collectCardMgrFee() {
        LambdaQueryWrapper<CardMgrFeeDO> lqw = new LambdaQueryWrapper<CardMgrFeeDO>();
        lqw.eq(CardMgrFeeDO::getStatus,"0");
        List<CardMgrFeeDO> mgrFeeDOS = cardMgrFeeMapper.selectList(lqw);
        if (mgrFeeDOS.size() > 0) {
            for (CardMgrFeeDO mgrFeeDO : mgrFeeDOS) {
                // 获取法定货币账号
                FaitWalletDO faitWalletDO = faitWalletMapper.selectOne(new LambdaQueryWrapper<FaitWalletDO>()
                    .eq(FaitWalletDO::getUid, mgrFeeDO.getUid())
                    .eq(FaitWalletDO::getCurrency, "USD")
                    .last("limit 1"));
                if (faitWalletDO != null) {
                    BigDecimal balance = faitWalletDO.getAmount();
                    /**
                     * 扣除开卡费
                     */
                    BigDecimal balanceFund = balance.subtract(mgrFeeDO.getCollectAmount());
                    EcWalletBillDO ecWalletBillDO = new EcWalletBillDO();
                    ecWalletBillDO.setUid(mgrFeeDO.getUid());
                    ecWalletBillDO.setEcId(faitWalletDO.getId());
                    ecWalletBillDO.setAccountHistoryNo(mgrFeeDO.getCardNo());
                    ecWalletBillDO.setAccountNo(Convert.toStr(faitWalletDO.getId()));
                    ecWalletBillDO.setAmount(mgrFeeDO.getCollectAmount());
                    ecWalletBillDO.setBalanceFund(balanceFund);
                    ecWalletBillDO.setCurrency("USD");
                    ecWalletBillDO.setTransactedAt(Convert.toStr(System.currentTimeMillis()));
                    ecWalletBillDO.setTxnType(OpenCardTransactionType.CARD_MGR_FEE.getCode());
                    ecWalletBillDO.setTransactionNotes(OpenCardTransactionType.CARD_MGR_FEE.getInfo());
                    ecWalletBillDO.setStatus("success");
                    ecWalletBillDO.setTransactionType("decrease");
                    ecWalletBillMapper.insert(ecWalletBillDO);
                    /**
                     * 更新钱包
                     */
                    faitWalletService.fiatWalletCardUpdate(faitWalletDO.getUid(),"USD",mgrFeeDO.getCollectAmount(),"decrease",null);
                    mgrFeeDO.setUpdateAt(System.currentTimeMillis());
                    mgrFeeDO.setStatus("1");
                    cardMgrFeeMapper.updateById(mgrFeeDO);
                }
            }
        }
    }

    /**
     * 定时创建卡片管理费用（每月1日1点执行）
     */
//    @Scheduled(cron = "0 0 1 1 * ?")
    @Transactional(rollbackFor = Exception.class)
    public void createCardMgrFee() {
        BigDecimal openCardFee = BigDecimal.ZERO;
        FeeThaliVO feeThaliVO = feeThaliMapper.selectVoOne(new LambdaQueryWrapper<FeeThaliDO>()
            .eq(FeeThaliDO::getType, "card_mgt")
            .eq(FeeThaliDO::getStatus, "0")
            .last("limit 1"));
        if (feeThaliVO != null) {
            openCardFee = Convert.toBigDecimal(feeThaliVO.getFeeConfig());
        }
        String createMonth = DateUtil.timestampToDateStr();
        LambdaQueryWrapper<BankCardDO> lqw = new LambdaQueryWrapper<BankCardDO>();
        lqw.notIn(BankCardDO::getStatus, OpenCardStatus.CANCELLED.getCode(),OpenCardStatus.UNACTIVATED.getCode());
        List<BankCardDO> bankCardDOS = bankCardMapper.selectList(lqw);
        if (bankCardDOS.size() > 0) {
            List<CardMgrFeeDO> list = new ArrayList<>();
            for (BankCardDO bankCardDO : bankCardDOS) {
                CardMgrFeeDO cardMgrFeeDO = new CardMgrFeeDO();
                cardMgrFeeDO.setUid(bankCardDO.getUid());
                cardMgrFeeDO.setCardId(bankCardDO.getCardId());
                cardMgrFeeDO.setCardNo(bankCardDO.getCardNo());
                cardMgrFeeDO.setCollectAmount(openCardFee);
                cardMgrFeeDO.setCollectMonth(createMonth);
                cardMgrFeeDO.setCreateAt(System.currentTimeMillis());
                cardMgrFeeDO.setStatus("0");
                list.add(cardMgrFeeDO);
            }
            if (list.size() > 0) {
                cardMgrFeeMapper.insertBatch(list);
            }
        }
    }
}
